######################################################################
package Swignition::GenericParser::GRDDL;
######################################################################

use Clone qw(clone);
use CSS::RDFEASE qw(:standard);
use Swignition::Misc;
use Swignition::GenericParser::RDF;
use Swignition::GenericParser::RDFa;

sub consume
{
	my $this = shift;
	my @transformations;

	push @transformations, transformations_rel($this);
	push @transformations, transformations_attr($this);
	push @transformations, transformations_profile($this);
	push @transformations, transformations_namespace($this);
	
	foreach my $t (@transformations)
	{
		my $uri = URI->new($t);
		next if ($this->{NoFollow}->{ $uri->host });
	
		my $request  = HTTP::Request->new(GET => $t);
		$request->header('Accept', 'application/xslt+xml, '
										 . 'text/xslt, '
										 . 'text/xsl, '
										 . 'text/x-rdf+css, '
										 . 'text/css');
		my $response = $this->get_ua->request($request);

		if ($response->header('content-type') =~ /(xslt|xml)/i)
		{
			my $parser     = XML::LibXML->new();
			my $xslt       = XML::LibXSLT->new();
			my $style_doc  = $parser->parse_string($response->content);

			my $stylesheet;
			eval { $stylesheet = $xslt->parse_stylesheet($style_doc); };
			
			unless ($@)
			{
				my $results    = $stylesheet->transform($this->{DOM});
				my $rdfxml     = $stylesheet->output_string($results);
			
				if ($stylesheet->media_type eq 'application/rdf+xml')
					{ Swignition::GenericParser::RDF::handle($this, $rdfxml); }
					
				# Need to put some other media types in here.
				
				else
					{ Swignition::GenericParser::RDF::handle($this, $rdfxml); }
				}
		}
		
		elsif ($response->header('content-type') =~ /^text\/(css|x\-rdf\+css)$/i)
		{
			# Get RDFa output of RDF-EASE as a XML::LibXML DOM structure.
			my $domOutput = rdfease_to_rdfa($response->content,
				$this->{DOM}->documentElement->toString,
				1);
			
			# Temporarily switch DOMs.
			my $tmp = $this->{DOM};
			$this->{DOM} = $domOutput;
			
			# Consume RDFa
			Swignition::GenericParser::RDFa::consume($this);
			
			# Restore original DOM to its rightful place.
			$this->{DOM} = $tmp;
		}
	}
}

sub is_enabled
{
	my $this = shift;
	return ($this->{DOM} && $this->{'options'}->{'p_grddl'});
}

# TODO - check with spec: are we supposed to do this on every element?
sub transformations_attr
{
	my $this = shift;
	my @transformations;

	my $attr = $this->{DOM}->documentElement->getAttributeNS(
		'http://www.w3.org/2003/g/data-view#', transformation);
	my @t = split /\s+/, $attr;
	foreach my $t (@t)
	{
		next unless ($t =~ /[a-z0-9\.]/i);
		push @transformations, $this->uri($t);
	}
	
	return @transformations;
}

sub transformations_namespace
{
	my $this = shift;
	my @transformations;

	# We skip namespaces for (X)HTML. The XHTML namespace only contains an RDFa
	# transformation, and we have native support for RDFa anyway.
	if ($this->{options}->{grddl_fetch}
	&&  ('Swignition::HtmlParser' ne ref $this))
	{
		# Here is the namespace URI
		my $nsuri    = $this->uri( $this->{DOM}->documentElement->namespaceURI );

		# NoFollow option
		my $uri = URI->new($nsuri);
		return @transformations
			if ($this->{NoFollow}->{ $uri->host });
		
		# Request the URI
		my $request  = HTTP::Request->new(GET => "$nsuri");
		my $response = Swignition::Misc::get_ua->request($request);

		# Set options for a recursive parse.
		my $opts          = clone($this->{options});
		$opts->{ua}       = $this->get_ua;
		$opts->{request}  = $request;
		$opts->{response} = $response;
		$opts->{base}     = "$uri";
		$opts->{p_rdfx}--;

		# Recursive parse.
		my $external_page = Swignition::GenericParser::new_by_type($response->content, $opts);
		
		# If MIME type was unrecognised by new_by_type, then try as RDF/XML.
		$external_page = Swignition::RdfXmlParser->new($response->content, $opts)
			if (!$external_page);

		# Need to parse the namespace document and find a triple
		# <nsuri> grddl:namespaceTransformation <transformuri> .
		if ($external_page)
		{
			my @vals;
			
			@vals = @{ $external_page->{'RDF'}->{"$nsuri"}->{'properties'}
				->{'http://www.w3.org/2003/g/data-view#namespaceTransformation'}
				->{'values'} }
				if ($external_page->{RDF}->{"$nsuri"});
			
			foreach my $val (@vals)
			{
				push @transformations, $val->toString
					if ($val->type);
			}
		}
	}
	
	return @transformations;
}

sub transformations_profile
{
	my $this = shift;
	my @transformations;

	# If this feature is enabled, and the parser is of the HTML flavour, then
	# get a list of transformations defined in the profiles.
	if ($this->{options}->{grddl_fetch}
	&& ('Swignition::HtmlParser' eq ref $this))
	{
		PROFILE: foreach my $p (keys %{$this->{Profiles}})
		{
			my $uri = URI->new($p);
			next if ($this->{NoFollow}->{ $uri->host });
		
			# Request the URI
			my $request  = HTTP::Request->new(GET => $p);
			my $response = Swignition::Misc::get_ua->request($request);

			# Set options for a recursive parse.
			my $opts          = clone($this->{options});
			$opts->{ua}       = $this->get_ua;
			$opts->{request}  = $request;
			$opts->{response} = $response;
			$opts->{base}     = "$uri";
			$opts->{p_rdfx}   = 0; # Don't do a recursive parse.

			# Recursive parse.
			$this->{Profiles}->{$p} = Swignition::GenericParser::new_by_type($response->content, $opts);
		
			# If MIME type was unrecognised by new_by_type, then try as HTML.
			$this->{Profiles}->{$p} = Swignition::HtmlParser->new($response->content, $opts)
				if (! $this->{Profiles}->{$p});

			# Need to parse the namespace document and find a triple
			# <profileuri> grddl:profileTransformation <transformuri> .
			if ((ref $this->{Profiles}->{$p}) =~ /^Swignition\:\:(.+)Parser/)
			{
				my @vals;
				
				@vals = @{ $this->{Profiles}->{$p}->{'RDF'}->{$p}->{'properties'}
					->{'http://www.w3.org/2003/g/data-view#profileTransformation'}
					->{'values'} }
					if ($this->{Profiles}->{$p}->{RDF}->{$p});
				
				foreach my $val (@vals)
				{
					push @transformations, $val->toString
						if ($val->type);
				}
			}
		}
	}
	
	return @transformations;
}

sub transformations_rel
{
	my $this = shift;
	my @transformations;
	
	# Get a list of locally defined transformations.
	if ($this->{Profiles}->{'http://www.w3.org/2003/g/data-view'}
		|| !$this->{options}->{grddl_strict_profiles} )
	{
		my $prop = $this->{RDF}->{ $this->uri }
			->property('http://www.w3.org/2003/g/data-view#transformation');
		if ($prop)
		{
			foreach my $v (@{$prop->valObjects})
			{
				my $uri = URI->new($v->toString);
				next if ($this->{NoFollow}->{ $uri->host });
				
				push @transformations, $v->toString if ($v->type);
			}
		}
	}
	
	return @transformations;
}

1;
